package com.keda.springdata_elasticsearch.repositories;

import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.query_dsl.BoolQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch._types.query_dsl.TermsQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.CreateOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexRequest;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.json.JsonData;
import com.keda.springdata_elasticsearch.config.LogConfigPropertires;
import com.keda.springdata_elasticsearch.dto.DispatchLogSearchDTO;
import com.keda.springdata_elasticsearch.dto.LogSearchDTO;
import com.keda.springdata_elasticsearch.dto.OperationErrorLogDTO;
import com.keda.springdata_elasticsearch.entity.OperationErrorLog;
import com.keda.springdata_elasticsearch.entity.OperationLog;
import com.keda.springdata_elasticsearch.utils.EsUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Repository;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 操作日志
 */
@Slf4j
@ConditionalOnMissingClass
@ConditionalOnProperty(prefix = "log", name = "strategy", havingValue = "es")
@Repository
public class OperationLogDao {

    @Autowired(required = false)
    private ElasticsearchClient elasticsearchClient;

    @Autowired(required = false)
    private ElasticsearchAsyncClient elasticsearchAsyncClient;

    @Autowired
    private LogConfigPropertires propertires;

    @Autowired
    private EsUtil esUtil;
    @Value("${avcs4.common.es.search.timeout:5s}")
    private String timeout;

    /**
     * 创建融合调度会议操作日志索引
     */
    public CreateIndexResponse createIndex() {
        return esUtil.buildIndex(propertires.getEs().getIndexName(), "es/app_logs_mapping.json");
    }

    /**
     * 创建融合调度操作索引
     */
    public CreateIndexResponse createDispatchLogIndex() {
        return esUtil.buildIndex(propertires.getEs().getDispatchLogIndexName(), "es/dispatch_operation_logs_mapping.json");

    }

    /**
     * 融合错误消息索引
     */
    public CreateIndexResponse createErrorLogIndex() {
        return esUtil.buildIndex(propertires.getEs().getErrorLogIndexName(), "es/error_log_mapping.json");
    }


    /**
     * 判断索引是否存在
     */
    public boolean existIndex() throws IOException {
        ExistsRequest existIndex = ExistsRequest.of(builder -> builder.index(propertires.getEs().getIndexName()));
        return elasticsearchClient.indices().exists(existIndex).value();
    }

    /**
     * 同步 删除索引
     */
    public DeleteIndexResponse deleteIndex() throws IOException {
        log.info("delete indexName:" + propertires.getEs().getIndexName());
        DeleteIndexRequest del = DeleteIndexRequest.of(builder -> builder.index(propertires.getEs().getIndexName()));
        return elasticsearchClient.indices().delete(del);
    }


    /**
     * 判断融合日志索引是否存在
     */
    public boolean existDispatchLogIndex() throws IOException {
        ExistsRequest existIndex = ExistsRequest.of(builder -> builder.index(propertires.getEs().getDispatchLogIndexName()));
        return elasticsearchClient.indices().exists(existIndex).value();
    }

    /**
     * 同步 删除融合日志索引
     */
    public DeleteIndexResponse deleteDispatchLogIndex() throws IOException {
        DeleteIndexRequest request = DeleteIndexRequest.of(builder -> builder.index(propertires.getEs().getDispatchLogIndexName()));
        log.info("delete indexName:" + propertires.getEs().getDispatchLogIndexName());
        return elasticsearchClient.indices().delete(request);
    }

    /**
     * 异步 添加文档 融合通信日志
     */
    public void insertDispatchDocumentAsync(OperationLog operationLog) {
        insertDocAsync(operationLog, propertires.getEs().getDispatchLogIndexName());

    }

    private void insertDocAsync(OperationLog operationLog, String indexName) {
        IndexRequest<Object> request = IndexRequest.of(builder -> builder
                .index(indexName) // 指定索引名
                .document(operationLog)); // 文档内容
        CompletableFuture<IndexResponse> future = elasticsearchAsyncClient.index(request);
        future.thenAccept(response -> {
            log.info("日志添加成功 {} ", response);
        }).exceptionally(e -> {
            log.error("日志添加失败 {}", e);
            return null;
        });
    }

    /**
     * 同步 添加文档
     */
    public IndexResponse insertDocument(OperationLog operationLog) throws IOException {
        IndexResponse response = elasticsearchClient.index(i -> i
                .index(propertires.getEs().getDispatchLogIndexName())
                .document(operationLog));
        log.info("文档添加结果 {} ", response);
        return response;
    }

    /**
     * 同步 添加文档
     */
    public void insertDocumentAsync(OperationLog operationLog) {
        insertDocAsync(operationLog, propertires.getEs().getIndexName());
    }

    /**
     * 同步 批量添加文档
     *
     * @param logList 文档列表
     */
    public BulkResponse batchInsertDocument(List<OperationLog> logList) throws IOException {
        String indexName = propertires.getEs().getIndexName();
        BulkRequest bulkRequest = getBulkRequest(logList, indexName);
        if (bulkRequest == null) {
            return null;
        }
        BulkResponse bulkres = elasticsearchClient.bulk(bulkRequest);
        log.info("批量新增数据的响应：" + bulkres);
        return bulkres;
    }

    private BulkRequest getBulkRequest(List<OperationLog> logList, String indexName) {
        if (CollectionUtils.isEmpty(logList)) {
            return null;
        }

        // 批量添加数据
        List<BulkOperation> opts = new ArrayList<>();
        for (OperationLog operationLog : logList) {
            CreateOperation<OperationLog> optObj = new CreateOperation.Builder<OperationLog>()
                    .index(indexName)
                    .document(operationLog)
                    .build();
            BulkOperation opt = new BulkOperation.Builder()
                    .create(optObj)
                    .build();
            opts.add(opt);
        }
        BulkRequest bulkRequest = new BulkRequest.Builder()
                .operations(opts)
                .build();
        return bulkRequest;
    }

    /**
     * 异步 批量添加文档
     *
     * @param logList 文档列表
     */
    public void batchInsertDocumentAsync(List<OperationLog> logList) {
        String indexName = propertires.getEs().getIndexName();
        BulkRequest bulkRequest = getBulkRequest(logList, indexName);
        CompletableFuture<BulkResponse> future = elasticsearchAsyncClient.bulk(bulkRequest);
        future.thenAccept(response -> {
            log.info("日志添加成功 {} ", response);
        }).exceptionally(e -> {
            log.error("日志添加失败 {}", e);
            return null;
        });
    }

    /**
     * 异步 更新文档
     */
    public void updateDocumentAsync(String id, OperationLog operationLog) throws IOException {
        CompletableFuture<UpdateResponse<OperationLog>> future = elasticsearchAsyncClient.update(u -> u
                .doc(operationLog)
                .index(propertires.getEs().getIndexName())
                .id(id), OperationLog.class);
        future.thenAccept(response -> {
            log.info("日志修改成功 {} ", response);
        }).exceptionally(e -> {
            log.error("日志修改失败 {}", e);
            return null;
        });
    }

    public SearchResponse<OperationLog> search(LogSearchDTO searchDTO) throws IOException {
        SearchRequest request = buildSearchRequest(searchDTO);
        SearchResponse<OperationLog> search = elasticsearchClient.search(request, OperationLog.class);
        search.hits().hits().forEach(hit -> {
            OperationLog source = hit.source();
            if (null != source) {
                source.setId(hit.id());
            }
        });
        return search;
    }

    public List<OperationLog> searchScroll(LogSearchDTO searchDTO) throws IOException {
        String indexName = propertires.getEs().getIndexName();
        String scrollId = null;
        List<OperationLog> result = new ArrayList<>();
        try {
            Query query = getCommonSearchSourceBuilder(searchDTO);
            SearchRequest searchRequest = null;
            if(!StringUtils.isEmpty(searchDTO.getSortField())){
                SortOrder sortOrder = SortOrder.Asc.toString().equals(searchDTO.getSortOrder()) ? SortOrder.Asc : SortOrder.Desc;
                searchRequest = SearchRequest.of(s -> s.index(indexName)
                        .scroll(time -> time.time("1m")).size(5000)
                        .sort(sort -> sort.field(f -> f.field(searchDTO.getSortField()).order(sortOrder)))
                        .query(query));
            }else{
                searchRequest= SearchRequest.of(s -> s.index(indexName)
                        .scroll(time -> time.time("1m")).size(5000)
                        .query(query));
            }
            SearchResponse<OperationLog> searchResponse = elasticsearchClient.search(searchRequest, OperationLog.class);
            List<Hit<OperationLog>> hits = searchResponse.hits().hits();
            setId(result, hits);
            scrollId = searchResponse.scrollId();
            while (hits.size() != 0) {
                SearchResponse<OperationLog> oldResonse = searchResponse;
                ScrollResponse<OperationLog> scroll = elasticsearchClient.scroll(s -> s
                                .scrollId(oldResonse.scrollId())
                                .scroll(Time.of(t -> t.time("1m"))
                                ),
                        OperationLog.class);
                scrollId = scroll.scrollId();
                hits = scroll.hits().hits();
                setId(result, hits);
            }
        } finally {
            if (StringUtils.isNotBlank(scrollId)) {
                //清除滚屏
                try {
                    List<String> list = new ArrayList<>();
                    list.add(scrollId);
                    elasticsearchClient.clearScroll(s -> s.scrollId(list));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return result;
    }

    private void setId(List<OperationLog> result, List<Hit<OperationLog>> hits) {
        for (Hit<OperationLog> hit : hits) {
            OperationLog source = hit.source();
            if (null != source) {
                source.setId(hit.id());
                result.add(source);
            }
        }
    }

    private SearchRequest buildSearchRequest(LogSearchDTO searchDTO) {
        Query query = getCommonSearchSourceBuilder(searchDTO);
        SortOrder sortOrder = SortOrder.Asc.toString().equals(searchDTO.getSortOrder()) ? SortOrder.Asc : SortOrder.Desc;
        return SearchRequest.of(s -> s.index(propertires.getEs().getIndexName())
                .query(query)
                .sort(sort -> sort.field(f -> f.field(searchDTO.getSortField()).order(sortOrder)))
                .from(searchDTO.getPageNo() * searchDTO.getPageSize())
                .size(searchDTO.getPageSize()).timeout(timeout));
    }

    private Query getCommonSearchSourceBuilder(LogSearchDTO searchDTO) {
        // meetingId
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        if (!CollectionUtils.isEmpty(searchDTO.getMeetingIds())) {
            List<FieldValue> words = searchDTO.getMeetingIds().stream().map(meetingId -> new FieldValue.Builder().stringValue(meetingId).build()).collect(Collectors.toList());
            TermsQuery termQuery = new TermsQuery.Builder()
                    .field("meetingId")
                    .terms(term -> term.value(words))
                    .build();
            boolQuery.must(s -> s.terms(termQuery));
        }
        // moudle
        if (!StringUtils.isEmpty(searchDTO.getMoudle())) {
            boolQuery.must(mat -> mat.match(s -> s.field("moudle").query(searchDTO.getMoudle())));
        }
        // event
        if (!StringUtils.isEmpty(searchDTO.getEvent())) {
            boolQuery.must(query -> query.match(match -> match.field("event").query(searchDTO.getEvent())));
        }
        // operationType
        if (!StringUtils.isEmpty(searchDTO.getOperationType())) {
            boolQuery.must(query -> query.term(match -> match.field("operationType").value(searchDTO.getOperationType())));
        }
        // createdBy
        if (!StringUtils.isEmpty(searchDTO.getCreatedBy())) {
            boolQuery.must(query -> query.term(term -> term.field("createdBy").value(searchDTO.getCreatedBy())));
        }
        // 日期
        if (searchDTO.getStartTime() != null || searchDTO.getEndTime() != null) {
            boolQuery.must(queryBuilder2 -> queryBuilder2
                    .range(rangeQueryBuilder -> rangeQueryBuilder
                            .field("createdTime").
                                    gte(JsonData.fromJson(String.valueOf(searchDTO.getStartTime().getTime()))).
                                    lte(JsonData.fromJson(String.valueOf(searchDTO.getEndTime().getTime())))));
        }
        // 设备名称
        if (!StringUtils.isEmpty(searchDTO.getDeviceName())) {
            boolQuery.must(query -> query.bool(bool -> bool
                    .should(s -> s.match(match -> match.field("devices").query(searchDTO.getDeviceName())))
                    .should(s -> s.match(match -> match.field("deviceNames").query(searchDTO.getDeviceName())))));
        }
        // 按照时间排序
        if (!StringUtils.isEmpty(searchDTO.getSortField())) {
            searchDTO.setSortField("createdTime");
        }
        String order = searchDTO.getSortOrder();
        if (!StringUtils.isEmpty(searchDTO.getSortOrder()) && !searchDTO.getSortOrder().equalsIgnoreCase("desc")) {
            order = SortOrder.Asc.toString();
        }
        searchDTO.setSortOrder(order);
        return Query.of(query -> query.bool(s -> boolQuery));
    }

    /**
     * 根据id删除数据
     *
     * @param id id
     */
    public void deleteById(String id) {
        try {
            elasticsearchClient.delete(s -> s.index(propertires.getEs().getIndexName()).id(id));
        } catch (IOException e) {
            log.error("es删除数据异常{}", e.getMessage());
        }
    }

    /**
     * 条件删除
     */
    public void deleteQuery(String meetingId) {
        try {
            elasticsearchClient.deleteByQuery(t -> t.query(query -> query
                    .term(term -> term
                            .field("meetingId").value(meetingId)))
                    .index(propertires.getEs().getIndexName())
                    .refresh(true));
        } catch (Exception e) {
            log.error("es删除数据异常{}", e.getMessage());
        }
    }

    /**
     * 删除小于指定日期的日志数据
     */
    public void deleteByDateTimeBefore(long dateTime) {
        try {
            elasticsearchClient.deleteByQuery(builder -> builder
                    .query(query -> query
                            .range(range -> range
                                    .field("createdTime")
                                    .lte(JsonData.fromJson(String.valueOf(dateTime)))))
                    .index(propertires.getEs().getDispatchLogIndexName())
                    .refresh(true));
        } catch (Exception e) {
            log.error("es删除数据异常{}", e.getMessage());
        }
    }

    public SearchResponse<OperationLog> searchDispatchLog(DispatchLogSearchDTO logSearchDTO) throws IOException {
        SearchRequest request = buildSearchDispatchLogRequest(logSearchDTO);
        SearchResponse<OperationLog> search = elasticsearchClient.search(request, OperationLog.class);
        setId(search);
        return search;
    }

    private void setId(SearchResponse<OperationLog> search) {
        search.hits().hits().forEach(s->{
            OperationLog source = s.source();
            String id = s.id();
            if(null != source){
                source.setId(id);
            }
        });
    }

    private SearchRequest buildSearchDispatchLogRequest(DispatchLogSearchDTO logSearchDTO) {
        Query query = getCommonSearchDispatchLogSourceBuilder(logSearchDTO);
        SortOrder sortOrder = SortOrder.Asc.toString().equals(logSearchDTO.getSortOrder()) ? SortOrder.Asc : SortOrder.Desc;
        return SearchRequest.of(s -> s.index(propertires.getEs().getDispatchLogIndexName())
                .query(query)
                .sort(sort -> sort.field(f -> f.field(logSearchDTO.getSortField()).order(sortOrder)))
                .from(logSearchDTO.getPageNo() * logSearchDTO.getPageSize())
                .size(logSearchDTO.getPageSize()).timeout(timeout));
    }

    private Query getCommonSearchDispatchLogSourceBuilder(DispatchLogSearchDTO logSearchDTO) {
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        // name
        if (!CollectionUtils.isEmpty(logSearchDTO.getIds())) {
            boolQuery.must(idquery -> idquery.ids(id -> id.values(logSearchDTO.getIds())));
        }
        // name
        if (StringUtils.isNotBlank(logSearchDTO.getName())) {
            boolQuery.must(mat -> mat.match(s -> s.field("name").query(logSearchDTO.getName())));
        }
        // username
        if (StringUtils.isNotBlank(logSearchDTO.getUsername())) {
            boolQuery.must(mat -> mat.match(s -> s.field("username").query(logSearchDTO.getUsername())));
        }
        // event
        if (StringUtils.isNotBlank(logSearchDTO.getNameIp())) {
            boolQuery.must(mat -> mat.term(s -> s.field("ip").value(logSearchDTO.getNameIp())));
        }
        // moudle
        if (StringUtils.isNotBlank(logSearchDTO.getMoudle())) {
            List<String> list = Arrays.asList(logSearchDTO.getMoudle().split(","));
            List<FieldValue> words = list.stream().map(meetingId -> new FieldValue.Builder().stringValue(meetingId).build()).collect(Collectors.toList());
            TermsQuery termQuery = new TermsQuery.Builder()
                    .field("meetingId")
                    .terms(term -> term.value(words))
                    .build();
            boolQuery.must(s -> s.terms(termQuery));
        }
        // event
        if (StringUtils.isNotBlank(logSearchDTO.getEvent())) {
            boolQuery.must(mat -> mat.match(s -> s.field("event").query(logSearchDTO.getEvent())));
        }
        // content
        if (StringUtils.isNotBlank(logSearchDTO.getContent())) {
            boolQuery.must(mat -> mat.match(s -> s.field("content").query(logSearchDTO.getContent())));
        }
        //滤掉掉createdTime字段不存在的数据
        boolQuery.must(mat -> mat.exists(s -> s.field("createdTime")));
        // 日期
        if (logSearchDTO.getStartTime() != null || logSearchDTO.getEndTime() != null) {
            boolQuery.must(queryBuilder2 -> queryBuilder2
                    .range(rangeQueryBuilder -> rangeQueryBuilder
                            .field("createdTime").
                                    gte(JsonData.fromJson(String.valueOf(logSearchDTO.getStartTime().getTime()))).
                                    lte(JsonData.fromJson(String.valueOf(logSearchDTO.getEndTime().getTime())))));
        }
        // 最长查询时间
        // 按照时间排序
        if (StringUtils.isBlank(logSearchDTO.getSortField())) {
            logSearchDTO.setSortField("createdTime");
        }
        SortOrder sortOrder = SortOrder.Desc;
        if (StringUtils.isNotBlank(logSearchDTO.getSortOrder()) && !logSearchDTO.getSortOrder().equalsIgnoreCase("desc")) {
            sortOrder = SortOrder.Asc;
            logSearchDTO.setSortOrder(sortOrder.toString());
        }
        return Query.of(query -> query.bool(s -> boolQuery));
    }

    public boolean existErrorLogIndex() throws IOException {
        return elasticsearchClient.indices().exists(s -> s.index(propertires.getEs().getErrorLogIndexName())).value();
    }


    /**
     * 同步 添加文档 融合通信日志
     */
    public void insertErroLogAsync(List<OperationErrorLog> operationLogs) throws IOException {
        String indexName = propertires.getEs().getErrorLogIndexName();
        BulkRequest bulkRequest = getErrorLogBulkRequest(operationLogs, indexName);
        CompletableFuture<BulkResponse> future = elasticsearchAsyncClient.bulk(bulkRequest);
        future.thenAccept(response -> {
            log.info("日志添加成功 {} ", response);
        }).exceptionally(e -> {
            log.error("日志添加失败 {}", e);
            return null;
        });
    }

    private BulkRequest getErrorLogBulkRequest(List<OperationErrorLog> logList, String indexName) {
        if (CollectionUtils.isEmpty(logList)) {
            return null;
        }

        // 批量添加数据
        List<BulkOperation> opts = new ArrayList<>();
        for (OperationErrorLog operationLog : logList) {
            CreateOperation<OperationErrorLog> optObj = new CreateOperation.Builder<OperationErrorLog>()
                    .index(indexName)
                    .document(operationLog)
                    .build();
            BulkOperation opt = new BulkOperation.Builder()
                    .create(optObj)
                    .build();
            opts.add(opt);
        }
        return new BulkRequest.Builder()
                .operations(opts)
                .build();
    }

    public SearchResponse<OperationErrorLog> searchErrorLog(OperationErrorLogDTO operationErrorLog) throws IOException {
        SearchRequest request = buildSearchErrorLogRequest(operationErrorLog);
        return elasticsearchClient.search(request, OperationErrorLog.class);
    }

    private SearchRequest buildSearchErrorLogRequest(OperationErrorLogDTO operationErrorLog) {
        Query query = getCommonSearchErrorLogSourceBuilder(operationErrorLog);
        SortOrder sortOrder = SortOrder.Asc.toString().equals(operationErrorLog.getSortOrder()) ? SortOrder.Asc : SortOrder.Desc;
        return SearchRequest.of(s -> s.index(propertires.getEs().getErrorLogIndexName())
                .query(query)
                .sort(sort -> sort.field(f -> f.field(operationErrorLog.getSortField()).order(sortOrder)))
                .from(operationErrorLog.getPageNo() * operationErrorLog.getPageSize())
                .size(operationErrorLog.getPageSize()).timeout(timeout));
    }

    private Query getCommonSearchErrorLogSourceBuilder(OperationErrorLogDTO operationErrorLog) {
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        // 日期
        if (operationErrorLog.getStartTime() != null || operationErrorLog.getEndTime() != null) {
            boolQuery.must(queryBuilder2 -> queryBuilder2
                    .range(rangeQueryBuilder -> rangeQueryBuilder
                            .field("createdTime").
                                    gte(JsonData.fromJson(String.valueOf(operationErrorLog.getStartTime().getTime()))).
                                    lte(JsonData.fromJson(String.valueOf(operationErrorLog.getEndTime().getTime())))));
        }
        //uuid
        if (StringUtils.isNotBlank(operationErrorLog.getUuId())) {
            boolQuery.must(query -> query.match(match -> match.field("uuId").query(operationErrorLog.getUuId())));
        }
        // createdUser
        if (CollectionUtils.isNotEmpty(operationErrorLog.getCreatedUsers())) {
            StringBuilder value = new StringBuilder();
            operationErrorLog.getCreatedUsers().forEach(str -> {
                value.append("").append(str);
            });
            boolQuery.must(query -> query.match(match -> match.field("createdUser").query(value.toString())));
        }

        // username
        if (StringUtils.isNotBlank(operationErrorLog.getMoudle())) {
            boolQuery.must(query -> query.match(match -> match.field("moudle").query(operationErrorLog.getMoudle())));
        }

        // errorCode
        if (StringUtils.isNotBlank(operationErrorLog.getErrorCode())) {
            boolQuery.must(query -> query.match(match -> match.field("errorCode").query(operationErrorLog.getErrorCode())));
        }
        // errorType
        if (CollectionUtils.isNotEmpty(operationErrorLog.getErrorTypes())) {
            List<FieldValue> words = operationErrorLog.getErrorTypes().stream().map(meetingId -> new FieldValue.Builder().stringValue(meetingId).build()).collect(Collectors.toList());
            TermsQuery termQuery = new TermsQuery.Builder()
                    .field("errorType")
                    .terms(term -> term.value(words))
                    .build();
            boolQuery.must(s -> s.terms(termQuery));
        }
        // 按照时间排序
        if (StringUtils.isBlank(operationErrorLog.getSortField())) {
            operationErrorLog.setSortField("createdTime");
        }
        SortOrder sortOrder = SortOrder.Desc;
        if (StringUtils.isNotBlank(operationErrorLog.getSortOrder()) && !operationErrorLog.getSortOrder().equalsIgnoreCase("desc")) {
            sortOrder = SortOrder.Asc;
            operationErrorLog.setSortOrder(sortOrder.toString());
        }
        return Query.of(query -> query.bool(s -> boolQuery));
    }

    public SearchResponse<OperationLog> exportByIds(List<String> ids) throws IOException {
        String indexName = propertires.getEs().getDispatchLogIndexName();
        Query query = getCommonSearchExportByIdsSourceBuilder(ids);

        Integer size = CollectionUtils.isNotEmpty(ids) ? ids.size() : 100;
        SearchRequest request = SearchRequest.of(s -> s.index(indexName)
                .query(query)
                .sort(sort -> sort.field(f -> f.field("createdTime").order(SortOrder.Desc)))
                .from(0)
                .size(size)
                .timeout(timeout));
        return elasticsearchClient.search(request, OperationLog.class);
    }

    private Query getCommonSearchExportByIdsSourceBuilder(List<String> ids) {
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();
        if (CollectionUtils.isNotEmpty(ids)) {
            boolQuery.must(s ->s.ids(id -> id.values(ids)));
        }
        return Query.of(query -> query.bool(s -> boolQuery));
    }


    public SearchResponse<OperationLog> exportAll(DispatchLogSearchDTO logSearchDTO) throws IOException {
        String indexName = propertires.getEs().getDispatchLogIndexName();
        Query query = getCommonSearchDispatchLogSourceBuilder(logSearchDTO);
        SearchRequest request = SearchRequest.of(s -> s.index(indexName)
                .query(query)
                .sort(sort -> sort.field(f -> f.field("createdTime").order(SortOrder.Desc)))
                .from(0)
                .timeout(timeout));
        return elasticsearchClient.search(request, OperationLog.class);
    }

}
